from gmsh_parser import gmsh_parser
import json
from pathlib import Path
import re
import mat

main_json = {
    "configuration": {
        "name": "P52",
        "method": "FEM",
        "unknown": ["Displace", "Pore"],
        "displace_pattern": ["Standard", "Signed", "Branch"],
        "equation": "Static",
        "solver": "Implicit",
        "load": "Incremental",
        "plane_stress": "false"
    },
    "io": {
        "log": {
            "log_level": "info",
            "detail_file_name": ""
        },
        "breakpoint": "",
        "output": {
            "path": ""
        }
    },
    "calculation": {
        "paralleled": "true",
        "time_step": {
            "theta": 0.8,
            "large_defomation": "false"
        },
        "iteration": {
            "max_time": 100,
            "nonlinear_scheme": "initial_stress",
            "tolerance": {
                "relative": 0.01,
                "absolute": 0
            }
        },
        "xfem": {
            "active": "true",
            "branch_enrich_radius": 0,
            "crack_segment": {
                "default_delta_length": 0.03,
                "gauss_num": 4
            },
            "sif_integral": {
                "domain": {
                    "shape": "circle",
                    "radius": 9
                },
                "qfunction": {
                    "exponent": 1
                }
            }
        },
        "gravity_scheme": "k0",
        "water_density": {
            "value": 10,
            "unit": "kN/m^3"
        },
        "atm": {
            "value": 100,
            "unit": "kPa"
        }
    },
    "topology": {
        "shape_function_degree":
        1,
        "elem_nodes_order":
        "clockwise",
        "elem_gauss_num": [{
            "name": "Segment",
            "value": 3
        }, {
            "name": "Triangle",
            "value": 3
        }, {
            "name": "Quadrangle",
            "value": 4
        }, {
            "name": "Tetrahedral",
            "value": 4
        }, {
            "name": "Tri_prism",
            "value": 6
        }, {
            "name": "Octahedral",
            "value": 8
        }],
        "cracks": [],
        "nodes": [],
        "elements": []
    },
    "materials": [],
    "init_condition": {
        "init_displacement": [],
        "init_pore": []
    },
    "phases": []
}

phase_json = {
    "id": 0,
    "start_time": 0,
    "end_time": 10,
    "delta_time": 10,
    "element_num": 9,
    "boundary_condition": {
        "dirichlet": [],
        "neumann": []
    }
}

mat_json = {
    mat.elastic.name: mat.elastic.json,
    mat.DuncanChang.name: mat.DuncanChang.json,
    mat.CamClay.name: mat.CamClay.json,
    mat.DruckPrager.name: mat.DruckPrager.json
}


class gmsh2json(gmsh_parser):
    def __init__(self):
        gmsh_parser.__init__(self)
        self.root = main_json

    def save(self, path_str=""):
        if path_str:
            path = Path(path_str)
            assert (path.suffix == ".xml")
        else:
            path = self.m_filename.with_suffix(".json")
        print("\n5. file is saved to ", path)
        with open(path, 'w') as f:
            json.dump(self.root, f, indent=4, separators=(',', ': '))

    def writeMesh(self):
        nodes_root = self.root["topology"]["nodes"]
        elems_root = self.root["topology"]["elements"]
        for elem in self.m_domain.elem_list:
            elems_root.append(self.elem2json(elem))
        for node in self.m_domain.node_list.values():
            nodes_root.append(self.node2json(node))

    def writeMaterials(self):
        root = self.root["materials"]
        for mat_id, mat_type in self.m_mats.items():
            new_mat_json = mat_json[mat_type]
            new_mat_json["id"] = mat_id
            root.append(new_mat_json)

    def writeBoundary(self):
        for phase_id, phase in self.m_phases.items():
            new_phase_json = phase_json
            new_phase_json["id"] = phase_id
            self.root["phases"].append(new_phase_json)
            for bcnode in phase.m_dirichlet.node_list.values():
                new_phase_json["boundary_condition"]["dirichlet"].append(
                    self.bcnode2json(bcnode))
            for bcnode in phase.m_neumann.node_list.values():
                new_phase_json["boundary_condition"]["neumann"].append(
                    self.bcnode2json(bcnode))

    def writeCrack(self):
        for crack_id, crack in self.m_cracks.items():
            new_crack_json = {"nodes": [], "elements": []}
            self.root["topology"]["cracks"].append(new_crack_json)
            for elem in self.m_domain.elem_list:
                new_crack_json["elements"].append(self.elem2json(elem))
            for node in self.m_domain.node_list.values():
                new_crack_json["nodes"].append(self.node2json(node))

    def node2json(self, node):
        root = {}
        root["id"] = int(node.id)
        root["coord"] = [int(node.x), int(node.y), int(node.z)]
        return root

    def bcnode2json(self, bcnode):
        root = {}
        root["node"] = bcnode.id
        root["dof"] = bcnode.dof
        root["type"] = "Linear"
        root["start"] = bcnode.svalue
        root["end"] = bcnode.evalue
        return root

    def elem2json(self, elem):
        root = {}
        root["id"] = self.m_elem_num
        self.m_elem_num += 1
        root["type"] = gmsh_parser.m_elem_types[elem.type]
        matchObj = re.match(".*mat(\\d+)_.*", elem.info)
        root["mat"] = int(matchObj.group(1))
        root["nodes"] = []
        for index in range(len(elem.plist)):
            root["nodes"].append(int(elem.plist[index]))
        return root


if (__name__ == "__main__"):
    obj = gmsh2json()
    obj.importGmsh("example.msh")
    obj.write()
